#include "args.h"

z_arg_buffer z_arg_buffer_init(z_size s, char *u)
{
	z_arg_buffer tmp;
	tmp.name = NULL;
	tmp.version = NULL;
	tmp.author = NULL;
	tmp.year = 0;
	tmp.usage = u;
	tmp.buf = (z_arg *)malloc(sizeof(z_arg)*s);
	memset(tmp.buf, 0, sizeof(z_arg)*s);
	tmp.head = 0;
	tmp.size = s;
	return tmp;
}

int z_arg_buffer_release(z_arg_buffer ab)
{
	free(ab.buf);
	return 0;
}

int z_arg_buffer_sign(z_arg_buffer *ab, char *n, char *v, char *a, int y)
{
	ab->name = n;
	ab->version = v;
	ab->author = a;
	ab->year = y;
	return 0;
}

int z_arg_buffer_append(z_arg_buffer *ab, char *arg)
{
	return z_arg_buffer_append_with_shorthand(ab, arg, 0);
}

int z_arg_buffer_append_with_shorthand(z_arg_buffer *ab, char *arg, char a)
{
	z_arg tmp;
	tmp.arg = arg;
	tmp.a = a;
	tmp.val = NULL;
	tmp.flagged = 0;
	tmp.desc = NULL;
	tmp.examples = NULL;
	if (ab->head >= ab->size)
		return 1;
	ab->buf[ab->head++] = tmp;
	return 0;
}

z_size z_arg_buffer_find(z_arg_buffer *ab, char *arg)
{
	for (z_size i = 0; i < ab->head; i++)
	{
		if (strcmp(ab->buf[i].arg, arg) == 0)
			return i;
	}

	return ab->size;
}

int z_arg_buffer_describe(z_arg_buffer *ab, char *arg, char *desc)
{
	z_size idx = z_arg_buffer_find(ab, arg);
	if (idx == ab->size)
		return 1;

	ab->buf[idx].desc = desc;
	return 0;
}

int z_arg_buffer_example(z_arg_buffer *ab, char *arg, ...)
{
	z_size idx = z_arg_buffer_find(ab, arg);
	if (idx == ab->size)
		return 1;

	va_list ap;
	va_start(ap, arg);
	ab->buf[idx].examples = (char **)malloc(sizeof(char *)*8);
	memset(ab->buf[idx].examples, 0, sizeof(char *)*8);
	int n = 0;
	for (char *p = va_arg(ap, char *); p != NULL; p = va_arg(ap, char *))
	{
		if (n >= 7)
			break;
		ab->buf[idx].examples[n++] = p;
	}
	va_end(ap);
	return 0;
}

int z_arg_buffer_flag_get(z_arg_buffer *ab, char *arg)
{
	z_size idx = z_arg_buffer_find(ab, arg);
	if (idx == ab->size)
		return 0;
	return ab->buf[idx].flagged;
}

int z_arg_buffer_flag_set(z_arg_buffer *ab, char *arg, int f)
{
	z_size idx = z_arg_buffer_find(ab, arg);
	if (idx == ab->size)
		return 0;
	return (ab->buf[idx].flagged = f);
}

char *z_arg_buffer_value_get(z_arg_buffer *ab, char *arg)
{
	z_size idx = z_arg_buffer_find(ab, arg);
	if (idx == ab->size)
		return NULL;
	return ab->buf[idx].val;
}

char *z_arg_buffer_value_set(z_arg_buffer *ab, char *arg, char *v)
{
	z_size idx = z_arg_buffer_find(ab, arg);
	if (idx == ab->size)
		return NULL;
	return (ab->buf[idx].val = v);
}

int z_arg_buffer_dump(z_arg_buffer *ab)
{
	if (ab->name)
		printf("%s ", ab->name);
	if (ab->version)
		printf("%s ", ab->version);
	if (ab->name || ab->version)
		printf("\n");

	if (ab->author)
		printf("%s ", ab->author);
	if (ab->year != 0)
		printf("%i ", ab->year);
	if (ab->author || ab->year != 0)
		printf("\n");

	if (ab->name || ab->version || ab->author || ab->year != 0)
		printf("\n");

	printf(" usage: %s\n\n", ab->usage);

	printf(" options:\n");
	for (z_size i = 0; i < ab->head; i++)
	{
		printf("  ");
		if (ab->buf[i].a != 0)
			printf("-%c || ", ab->buf[i].a);
		printf("--%s", ab->buf[i].arg);
		if (ab->buf[i].examples)
		{
			printf("=");
			printf("%s", ab->buf[i].examples[0]);
			for (int j = 1; ab->buf[i].examples[j] != NULL; j++)
				printf("||%s", ab->buf[i].examples[j]);
			printf("||...");
		}
		printf("\n");
		if (ab->buf[i].desc)
			printf("%s\n\n", ab->buf[i].desc);
	}
	printf("  --help\n");
	printf("Display this help information.\n\n");
	printf("  --exit\n");
	printf("Exit the program after parsing this argument.\n\n");

	return 0;
}

int z_init_args(z_arg_buffer *ab, int argc, char *argv[])
{
	if (ab == NULL)
	{
		printf("warning: this binary is for testing and does not have implemented arguments.\n");
		return 0;
	}

	for (int i = 0; i < argc; i++)
	{
		if (argv[i][0] == '-' && argv[i][1] == '-')
		{
			char *a = argv[i]+2;
			
			if (strcmp(a, "help") == 0)
			{
				z_arg_buffer_dump(ab);
				return 1;
			}
			else if (strcmp(a, "exit") == 0)
			{
				return 1;
			}

			if (strchr(a, '=') != NULL)
			{
				char *v = strchr(a, '=')+1;
				*(strchr(a, '=')) = 0;
				z_size idx = z_arg_buffer_find(ab, a);
				if (idx == ab->size)
				{
					printf("error: unknown argument: %s (%s)\n", argv[i], a);
				}
				else
				{
					ab->buf[i].val = v;
					ab->buf[i].flagged = 1;
				}
			}
			else
			{
				z_size idx = z_arg_buffer_find(ab, a);
				if (idx == ab->size)
				{
					printf("error: unknown argument: %s (%s)\n", argv[i], a);
				}
				else
				{
					ab->buf[i].flagged = 1;
				}
			}
		}
		else if (argv[i][0] == '-')
		{
			int e = 0;
			for (z_size i = 0; i < ab->head; i++)
			{
				if (ab->buf[i].a == argv[i][1])
				{
					ab->buf[i].flagged = 1;
					e = 1;
					break;
				}
			}

			if (e == 0)
			{
				printf("error: unknown shorthand argument: %s (%c)\n", argv[i], argv[i][1]);
			}
		}
	}

	return 0;
}

